package com.kexio.user.service.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kexio.auth.util.AuthContextUtils;
import com.kexio.auth.context.TenantContextHolder;
import com.kexio.user.entity.Dept;
import com.kexio.user.entity.User;
import com.kexio.user.mapper.DeptMapper;
import com.kexio.user.mapper.UserMapper;
import com.kexio.user.service.DeptService;

/**
 * 部门服务实现类
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@Service
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements DeptService {

    private static final Logger logger = LoggerFactory.getLogger(DeptServiceImpl.class);

    @Autowired
    private DeptMapper deptMapper;
    
    @Autowired
    private UserMapper userMapper;

    @Override
    public List<Dept> getDeptTree() {
        String tenantId = TenantContextHolder.getCurrentTenantId();
        return getDeptTreeByTenant(tenantId);
    }

    @Override
    public List<Dept> getDeptTreeByTenant(String tenantId) {
        try {
            // 查询所有有效部门
            LambdaQueryWrapper<Dept> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Dept::getTenantId, tenantId)
                   .eq(Dept::getStatus, 1)
                   .orderByAsc(Dept::getLevel, Dept::getOrderNo);
            
            List<Dept> allDepts = list(wrapper);
            
            // 构建树形结构
            return buildDeptTree(allDepts, null);
        } catch (Exception e) {
            logger.error("获取部门树失败: tenantId={}", tenantId, e);
            return new ArrayList<>();
        }
    }

    @Override
    public Dept getDeptDetailById(String deptId) {
        try {
            Dept dept = getById(deptId);
            if (dept == null) {
                return null;
            }
            
            // 统计部门成员数量
            LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.eq(User::getDeptId, deptId)
                      .eq(User::getStatus, 1);
            long memberCount = userMapper.selectCount(userWrapper);
            
            // 统计子部门数量
            LambdaQueryWrapper<Dept> deptWrapper = new LambdaQueryWrapper<>();
            deptWrapper.eq(Dept::getParentId, deptId)
                      .eq(Dept::getStatus, 1);
            long childDeptCount = count(deptWrapper);
            
            // 设置统计信息（通过扩展属性）
            dept.setMemberCount((int) memberCount);
            dept.setChildDeptCount((int) childDeptCount);
            
            return dept;
        } catch (Exception e) {
            logger.error("获取部门详情失败: deptId={}", deptId, e);
            return null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveDept(Dept dept) {
        // 设置基本信息
        String tenantId = TenantContextHolder.getCurrentTenantId();
        String currentUserId = AuthContextUtils.getCurrentUserId();
        
        dept.setTenantId(tenantId);
        dept.setCreateBy(currentUserId);
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateBy(currentUserId);
        dept.setUpdateTime(LocalDateTime.now());
        
        // 设置部门层级
        if (StringUtils.hasText(dept.getParentId())) {
            Dept parentDept = getById(dept.getParentId());
            if (parentDept != null) {
                dept.setLevel(parentDept.getLevel() + 1);
            } else {
                dept.setLevel(1);
            }
        } else {
            dept.setLevel(1);
        }
        
        // 设置排序号
        if (dept.getOrderNo() == null) {
            dept.setOrderNo(getNextOrderNo(dept.getParentId()));
        }
        
        return save(dept);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateDept(Dept dept) {
        // 设置更新信息
        String currentUserId = AuthContextUtils.getCurrentUserId();
        dept.setUpdateBy(currentUserId);
        dept.setUpdateTime(LocalDateTime.now());
        
        // 如果修改了父部门，需要重新计算层级
        Dept existingDept = getById(dept.getId());
        if (existingDept != null && 
            !Objects.equals(existingDept.getParentId(), dept.getParentId())) {
            updateDeptLevel(dept);
        }
        
        return updateById(dept);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteDept(String deptId) {
        // 检查是否可以删除
        if (!canDelete(deptId)) {
            throw new RuntimeException("部门下存在子部门或用户，无法删除");
        }
        
        return removeById(deptId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteDepts(List<String> deptIds) {
        // 批量检查所有部门是否可删除
        List<java.util.Map<String, Object>> checkResults = baseMapper.batchCheckDeletable(deptIds);
        
        // 收集不可删除的部门
        List<String> undeletableDepts = new ArrayList<>();
        for (java.util.Map<String, Object> result : checkResults) {
            Object deptIdObj = result.get("dept_id");
            Object deletableObj = result.get("deletable");
            
            if (deptIdObj != null && deletableObj != null) {
                int deletable = ((Number) deletableObj).intValue();
                if (deletable == 0) {
                    undeletableDepts.add(String.valueOf(deptIdObj));
                }
            }
        }
        
        // 如果有不可删除的部门，抛出异常
        if (!undeletableDepts.isEmpty()) {
            throw new RuntimeException(
                "以下部门包含子部门或用户，无法删除: " + String.join(", ", undeletableDepts)
            );
        }
        
        // 所有部门都可删除，执行批量删除
        return removeByIds(deptIds);
    }

    @Override
    public List<String> getDeptAndChildIds(String deptId) {
        try {
            return deptMapper.selectDeptAndChildIds(deptId);
        } catch (Exception e) {
            logger.error("获取部门及子部门ID失败: deptId={}", deptId, e);
            return Arrays.asList(deptId);
        }
    }

    @Override
    public List<String> getChildDeptIds(String parentId) {
        try {
            return deptMapper.selectChildDeptIds(parentId);
        } catch (Exception e) {
            logger.error("获取子部门ID失败: parentId={}", parentId, e);
            return new ArrayList<>();
        }
    }

    @Override
    public String getUserDeptId(String userId, String tenantId) {
        try {
            return deptMapper.selectUserDeptId(userId, tenantId);
        } catch (Exception e) {
            logger.error("获取用户部门ID失败: userId={}, tenantId={}", userId, tenantId, e);
            return null;
        }
    }

    @Override
    public String getDeptPath(String deptId) {
        try {
            return deptMapper.selectDeptPath(deptId);
        } catch (Exception e) {
            logger.error("获取部门路径失败: deptId={}", deptId, e);
            return null;
        }
    }

    @Override
    public boolean isCodeUnique(String deptCode, String tenantId, String excludeId) {
        try {
            LambdaQueryWrapper<Dept> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Dept::getDeptCode, deptCode)
                   .eq(Dept::getTenantId, tenantId);
            
            if (StringUtils.hasText(excludeId)) {
                wrapper.ne(Dept::getId, excludeId);
            }
            
            return count(wrapper) == 0;
        } catch (Exception e) {
            logger.error("校验部门编码唯一性失败: code={}, tenantId={}, excludeId={}", 
                        deptCode, tenantId, excludeId, e);
            return false;
        }
    }

    @Override
    public boolean canDelete(String deptId) {
        try {
            // 检查是否有子部门
            LambdaQueryWrapper<Dept> deptWrapper = new LambdaQueryWrapper<>();
            deptWrapper.eq(Dept::getParentId, deptId)
                      .eq(Dept::getStatus, 1);
            if (count(deptWrapper) > 0) {
                return false;
            }
            
            // 检查是否有用户
            LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.eq(User::getDeptId, deptId)
                      .eq(User::getStatus, 1);
            return userMapper.selectCount(userWrapper) == 0;
        } catch (Exception e) {
            logger.error("检查部门是否可删除失败: deptId={}", deptId, e);
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean moveDept(String deptId, String newParentId, Integer targetOrder) {
        try {
            Dept dept = getById(deptId);
            if (dept == null) {
                return false;
            }
            
            dept.setParentId(newParentId);
            if (targetOrder != null) {
                dept.setOrderNo(targetOrder);
            }
            
            // 重新计算层级
            updateDeptLevel(dept);
            
            return updateById(dept);
        } catch (Exception e) {
            logger.error("移动部门失败: deptId={}, newParentId={}, targetOrder={}", 
                        deptId, newParentId, targetOrder, e);
            throw new RuntimeException("移动部门失败", e);
        }
    }

    @Override
    public List<Dept> getAvailableParentDepts(String deptId, String tenantId) {
        try {
            LambdaQueryWrapper<Dept> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Dept::getTenantId, tenantId)
                   .eq(Dept::getStatus, 1);
            
            if (StringUtils.hasText(deptId)) {
                // 排除自己
                wrapper.ne(Dept::getId, deptId);
                
                // 排除所有子部门
                List<String> childIds = getDeptAndChildIds(deptId);
                if (!CollectionUtils.isEmpty(childIds)) {
                    wrapper.notIn(Dept::getId, childIds);
                }
            }
            
            wrapper.orderByAsc(Dept::getLevel, Dept::getOrderNo);
            
            return list(wrapper);
        } catch (Exception e) {
            logger.error("获取可选父部门失败: deptId={}, tenantId={}", deptId, tenantId, e);
            return new ArrayList<>();
        }
    }

    @Override
    public Map<String, Object> getDeptStatistics(String tenantId) {
        try {
            Map<String, Object> stats = new HashMap<>();
            
            // 总部门数
            LambdaQueryWrapper<Dept> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Dept::getTenantId, tenantId)
                   .eq(Dept::getStatus, 1);
            long totalDepts = count(wrapper);
            stats.put("totalDepts", totalDepts);
            
            // 按层级统计
            List<Map<String, Object>> levelStats = new ArrayList<>();
            for (int level = 1; level <= 5; level++) {
                wrapper.clear();
                wrapper.eq(Dept::getTenantId, tenantId)
                       .eq(Dept::getStatus, 1)
                       .eq(Dept::getLevel, level);
                long count = count(wrapper);
                if (count > 0) {
                    Map<String, Object> levelStat = new HashMap<>();
                    levelStat.put("level", level);
                    levelStat.put("count", count);
                    levelStats.add(levelStat);
                }
            }
            stats.put("levelStats", levelStats);
            
            return stats;
        } catch (Exception e) {
            logger.error("获取部门统计信息失败: tenantId={}", tenantId, e);
            return new HashMap<>();
        }
    }

    @Override
    public List<Dept> buildDeptTree(List<Dept> depts, String parentId) {
        if (CollectionUtils.isEmpty(depts)) {
            return new ArrayList<>();
        }
        
        // 性能优化: 使用Map预处理父子关系
        return buildDeptTreeOptimized(depts, parentId);
    }
    
    /**
     * 优化的树形结构构建算法
     * 时间复杂度: O(n) vs 原来的O(n²)
     * 
     * @param depts 部门列表
     * @param rootParentId 根节点父ID
     * @return 树形结构的部门列表
     */
    private List<Dept> buildDeptTreeOptimized(List<Dept> depts, String rootParentId) {
        // 1. 按parentId分组，一次遍历建立索引 - O(n)
        Map<String, List<Dept>> parentChildrenMap = depts.stream()
                .collect(Collectors.groupingBy(
                    dept -> dept.getParentId() == null ? "NULL" : dept.getParentId(),
                    LinkedHashMap::new,  // 保持插入顺序
                    Collectors.toList()
                ));
        
        // 2. 递归构建树形结构，通过Map快速查找 - O(n)
        return buildTreeFromMap(parentChildrenMap, rootParentId == null ? "NULL" : rootParentId);
    }
    
    /**
     * 从预构建的Map中递归构建树形结构
     */
    private List<Dept> buildTreeFromMap(Map<String, List<Dept>> parentChildrenMap, String parentKey) {
        List<Dept> children = parentChildrenMap.get(parentKey);
        if (CollectionUtils.isEmpty(children)) {
            return new ArrayList<>();
        }
        
        // 设置子节点并排序
        return children.stream()
                .peek(dept -> {
                    // 递归设置子节点（通过Map查找，O(1)复杂度）
                    List<Dept> subChildren = buildTreeFromMap(parentChildrenMap, dept.getId());
                    dept.setChildren(subChildren);
                })
                .sorted(Comparator.comparing(Dept::getOrderNo, Comparator.nullsLast(Comparator.naturalOrder())))
                .collect(Collectors.toList());
    }

    /**
     * 获取下一个排序号
     */
    private Integer getNextOrderNo(String parentId) {
        try {
            LambdaQueryWrapper<Dept> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Dept::getParentId, parentId)
                   .orderByDesc(Dept::getOrderNo)
                   .last("LIMIT 1");
            
            Dept lastDept = getOne(wrapper, false);
            if (lastDept != null && lastDept.getOrderNo() != null) {
                return lastDept.getOrderNo() + 1;
            }
            return 1;
        } catch (Exception e) {
            logger.error("获取下一个排序号失败: parentId={}", parentId, e);
            return 1;
        }
    }

    /**
     * 更新部门层级
     */
    private void updateDeptLevel(Dept dept) {
        if (StringUtils.hasText(dept.getParentId())) {
            Dept parentDept = getById(dept.getParentId());
            if (parentDept != null) {
                dept.setLevel(parentDept.getLevel() + 1);
            } else {
                dept.setLevel(1);
            }
        } else {
            dept.setLevel(1);
        }
        
        // 递归更新所有子部门的层级
        updateChildDeptLevels(dept.getId(), dept.getLevel());
    }

    /**
     * ✅ 批量更新子部门层级（使用递归CTE，一条SQL搞定）
     */
    private void updateChildDeptLevels(String parentId, Integer parentLevel) {
        int updatedCount = baseMapper.batchUpdateChildDeptLevels(parentId, parentLevel);
        logger.info("批量更新子部门层级成功: parentId={}, parentLevel={}, updatedCount={}", 
                   parentId, parentLevel, updatedCount);
    }
}

